package com.ygq.exportdbstructure.config;

import com.ygq.exportdbstructure.model.DataSource;

import java.util.*;
import java.util.regex.Pattern;

/**
 * @author emc
 * @version 1.0
 * createTime 2025-10-30
 * description 数据库连接信息参数校验
 */
public class DataSourceValidator {

    // 使用Set集合提高查询效率
    private static final Set<String> SUPPORTED_DB_TYPES = Collections.unmodifiableSet(new HashSet<String>() {{
        add("mysql");
        add("oracle");
        add("dm");
        add("sqlserver");
        add("postgresql");
        add("doris");
    }});

    // 预编译正则表达式，提高IP验证性能 [1](@ref)
    private static final Pattern IP_PATTERN = Pattern.compile(
            "^(localhost|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,})$"
    );

    private static final Pattern DRIVER_CLASS_PATTERN = Pattern.compile(
            "^[a-zA-Z_$][a-zA-Z\\d_$]*(\\.[a-zA-Z_$][a-zA-Z\\d_$]*)*$"
    );

    // 使用HashMap替代switch-case提高可维护性
    private static final Map<String, String> DRIVER_MAPPING =
            Collections.unmodifiableMap(new HashMap<String, String>() {{
                put("mysql", "com.mysql.cj.jdbc.Driver");
                put("doris", "com.mysql.cj.driver.DmDriver");
                put("oracle", "oracle.jdbc.driver.OracleDriver");
                put("dm", "dm.jdbc.driver.DmDriver");
                put("sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
                put("postgresql", "org.postgresql.Driver");
            }});


    /**
     * 初始化数据库连接信息方法 - 使用final参数和局部变量
     */
    public static DataSource initAndValidate(final DataSource dataSource) {

        // 参数校验前置，快速失败 [4](@ref)
        validateNotEmpty("db_type", dataSource.getDb_type());
        validateNotEmpty("db_ip", dataSource.getDb_ip());
        validateNotEmpty("db_port", dataSource.getDb_port());
        validateNotEmpty("db_name", dataSource.getDb_name());
        validateNotEmpty("username", dataSource.getUsername());
        validateNotEmpty("password", dataSource.getPassword());
        validateNotEmpty("db_table_name", dataSource.getDb_table_name());

        // 创建配置对象
        final DataSource config = new DataSource();

        // 使用小写统一处理，避免大小写问题 [3](@ref)
        final String normalizedDbType = dataSource.getDb_type().toLowerCase();

        // 设置基本参数
        config.setDb_type(normalizedDbType);
        config.setDb_ip(dataSource.getDb_ip().trim());
        config.setDb_port(dataSource.getDb_port().trim());
        config.setDb_name(dataSource.getDb_name().trim());
        config.setUsername(dataSource.getUsername().trim());
        config.setPassword(dataSource.getPassword());
        config.setDb_table_name(dataSource.getDb_table_name().trim());

        // 自动设置驱动类名
        final String driverClassName = DRIVER_MAPPING.get(normalizedDbType);
        if (driverClassName != null) {
            config.setDriverClassName(driverClassName);
        }

        // 执行详细校验
        performDetailedValidation(config);

        return config;
    }

    /**
     * 详细的参数校验 - 拆分为小方法提高可读性 [7](@ref)
     */
    private static void performDetailedValidation(final DataSource config) {
        validateDbType(config.getDb_type());
        validateIpAddress(config.getDb_ip());
        validatePort(config.getDb_port());
        // 驱动类名在校验时不强制，因为前面已经自动设置
    }

    /**
     * 非空校验优化 - 使用StringUtils.isEmpty逻辑 [1](@ref)
     */
    private static void validateNotEmpty(final String fieldName, final String value) {
        if (value == null || value.trim().isEmpty()) {
            throw new IllegalArgumentException(fieldName + " 不能为空或空字符串");
        }
    }

    /**
     * 数据库类型校验优化 - 使用Set.contains提高性能
     */
    private static void validateDbType(final String dbType) {
        if (!SUPPORTED_DB_TYPES.contains(dbType.toLowerCase())) {
            throw new IllegalArgumentException(
                    String.format("不支持的数据库类型: %s。支持的类型: %s",
                            dbType, String.join(", ", SUPPORTED_DB_TYPES))
            );
        }
    }

    /**
     * IP地址校验优化 - 使用预编译正则表达式 [1](@ref)
     */
    private static void validateIpAddress(final String ip) {
        if (!IP_PATTERN.matcher(ip).matches()) {
            throw new IllegalArgumentException("IP地址格式不正确: " + ip);
        }

        // 详细IP段校验
        if (ip.matches("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$")) {
            final String[] parts = ip.split("\\.");
            for (final String part : parts) {  // 使用final参数 [1](@ref)
                final int num = Integer.parseInt(part);
                if (num < 0 || num > 255) {
                    throw new IllegalArgumentException("IP地址段超出范围: " + ip);
                }
            }
        }
    }

    /**
     * 端口号校验优化 - 避免重复解析
     */
    private static void validatePort(final String portStr) {
        try {
            final int port = Integer.parseInt(portStr);
            if (port < 1 || port > 65535) {
                throw new IllegalArgumentException("端口号必须在1-65535之间: " + port);
            }
        } catch (final NumberFormatException e) {
            throw new IllegalArgumentException("端口号必须是有效数字: " + portStr);
        }
    }

    /**
     * 生成JDBC URL的优化方法
     */
    public static String generateJdbcUrl(final DataSource config) {
        final String dbType = config.getDb_type().toLowerCase();
        final String ip = config.getDb_ip();
        final String port = config.getDb_port();
        final String dbName = config.getDb_name();

        switch (dbType) {
            case "mysql":
            case "doris":
                return String.format("jdbc:mysql://%s:%s/%s?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai",
                        ip, port, dbName);

            case "oracle":
                return String.format("jdbc:oracle:thin:@%s:%s:%s", ip, port, dbName);

            case "dm":
                return String.format("jdbc:dm://%s:%s/%s", ip, port, dbName);

            case "sqlserver":
                return String.format("jdbc:sqlserver://%s:%s;databaseName=%s;encrypt=false",
                        ip, port, dbName);

            case "postgresql":
                return String.format("jdbc:postgresql://%s:%s/%s", ip, port, dbName);

            default:
                throw new IllegalArgumentException("不支持的数据库类型: " + dbType);
        }
    }
}
